<?php
//-------------------------------------------------------------------------
// OVIDENTIA http://www.ovidentia.org
// Ovidentia is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, or (at your option)
// any later version.
// 
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//-------------------------------------------------------------------------
/**
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
 * @copyright Copyright (c) 2006 by CANTICO ({@link http://www.cantico.fr})
 */
include_once 'base.php';
require_once $GLOBALS['babInstallPath'] . '/addons/widgets/widgets/uploader.class.php';
include_once $GLOBALS['babInstallPath'].'utilit/path.class.php';
require_once $GLOBALS['babInstallPath'].'utilit/uploadincl.php';

/**
 * Constructs a Widget_FilePicker.
 *
 * @param string		$id			The item unique id.
 * @return Widget_FilePicker
 */
function Widget_FilePicker($id = null)
{
	return new Widget_FilePicker($id);
}


/**
 * A Widget_FilePicker is a widget that let the user upload files. 
 * by default, upload are commited to a temporary folder
 * 
 * value of this input widget is an array containing the list of files in the folder
 * 
 */
class Widget_FilePicker extends Widget_Uploader implements Widget_Displayable_Interface 
{
	const PREFIX_LENGTH = 6;
	const BASE64 	= 'BASE64';
	const QPRINT 	= 'QPRINT';
	const NONE		= '______';
	
	/**
	 * Folder used to save files
	 * @var bab_Path
	 */
	private $folder = null;
	
	
	/**
	 * state of folder
	 * true if the folder is a temporary directory
	 * false if the folder is a custom directory
	 * 
	 * 
	 * 
	 * @var bool
	 */
	private $temporary = null;
	
	
	/**
	 * Encoding method used to write files on filesystem
	 * null value used to disable encoding
	 * 
	 * @var string 		Widget_FilePicker::BASE64 | Widget_FilePicker::QPRINT | Widget_FilePicker::NONE
	 */
	private $encoding = null;
	

	/**
	 * An optional drop target associated to the file picker.
	 * (Files dropped on this item will be uploaded as if they
	 * had been selected with the filepicker).
	 * @var Widget_Item
	 */
	private $associatedDropTarget = null;

	protected $thumbWidth = 48;
	protected $thumbHeight = 48;
	
	/**
	 * url to default image
	 * @see Widget_ImagePicker::setDefaultImage()
	 * @var string URL
	 */
	protected $defaultImage = null;
	
	
	/**
	 * max size of a file in bytes
	 * @var int
	 */
	private $maxsize = null;

	/**
	 * @param string $id			The item unique id.
	 * @return Widget_DatePicker
	 */
	public function __construct($id = null)
	{
		parent::__construct($id);
		
		
		// set temporary folder
		$addon = bab_getAddonInfosInstance('widgets');
		$this->folder = new bab_Path($addon->getUploadPath());
		$this->folder->push(__CLASS__);
		$this->folder->push(session_id());
		$this->temporary = true;
		
		// autodetect best encoding method
		if (function_exists('quoted_printable_encode') || function_exists('imap_8bit')) {
			$this->encoding = self::QPRINT;
		} else {
			$this->encoding = self::BASE64;
		}

		$this->setMetadata('selfpage', bab_getSelf());
		$this->setMetadata('title', widget_translate('Add file'));
		$this->setMetadata('loading', widget_translate('Loading...'));
		$this->setMetadata('msgerror', widget_translate('Error while uploading file'));
		$this->setMetadata('msgerror_delete', widget_translate('Error while deleting file'));
		$this->setMetadata('msgerror_duplicate', widget_translate('The file %s already exists, replace?'));
		$this->setMetadata('msgdelete', widget_translate('Do you really want to delete this file?'));
		$this->setMetadata('one_file_mode', false);
		$this->setMetadata('display_existing_files', true);
		$this->setMetadata('uploadOrDeleteUid', uniqid());
		$this->setMetadata('thumbnailUid', uniqid());
		
		$this->addClass('icon-left-16')
			->addClass('icon-16x16')
			->addClass('icon-left');	

		bab_functionality::includeFile('Icons');
		
		$this->setMetadata('fileclasses', array('widget-filepicker-file'));
		$this->setMetadata('deleteclasses', array('widget-layout-vbox-item', Func_Icons::ACTIONS_EDIT_DELETE, 'icon', 'widget-filepicker-file-delete'));
		$this->setMetadata('loadingclasses', array('widget-layout-vbox-item', Func_Icons::STATUS_CONTENT_LOADING, 'icon', 'widget-filepicker-loading'));

	}
	
	/**
	 * set widget name and use it as temporary folder
	 * 
	 * @param	string	$name
	 * 
	 * @see programs/widgets/Widget_Widget#setName($name)
	 * 
	 * @return Widget_FilePicker
	 */
	public function setName($name)
	{
		if ($this->temporary) {
			$this->folder->push($name);
		}
		
		return parent::setName($name);
	}
	
	
	
	/**
	 * Set title as metadata for javascript, the title is used as button label
	 * @param	string	$title
	 * @see programs/widgets/Widget_Item#setTitle($title)
	 * 
	 * @return Widget_FilePicker
	 */
	public function setTitle($title)
	{
		$this->setMetadata('title', $title);
		return parent::setTitle($title);
	}
	
	
	/**
	 * Do not display already uploaded files in widget
	 * 
	 * @return Widget_FilePicker
	 */
	public function hideFiles()
	{
		$this->setMetadata('display_existing_files', false);
		return $this;
	}
	
	/**
	 * Set/unset the one-file mode.
	 * If active, all files currently in the associated folder are deleted
	 * before the new file is uploaded.
	 * 
	 * @param $active		True to activate one-file mode, false to deactivate.
	 * @return Widget_FilePicker
	 */
	public function oneFileMode($active = true)
	{
		$this->addClass('widget-filepicker-onefilemode');
		$this->setMetadata('one_file_mode', $active);
		if ($active) {
			$this->setMetadata('title', widget_translate('Select file'));
		} else {
			$this->setMetadata('title', widget_translate('Add file'));
		}
		
		return $this;
	}
	


	/**
	 * set the path of folder where the files will be stored
	 * the folder must be created before
	 * 
	 * @see bab_Path::createDir() 
	 *
	 * @param bab_Path $path
	 * @return Widget_FilePicker
	 */
	public function setFolder(bab_Path $path)
	{
		assert('$path->isAbsolute(); /* The "path" parameter must be an absolute path to folder */');
		
		$this->folder = $path;
		$this->temporary = false;
		return $this;
	}
	
	/**
	 * Get the folder where the files are uploaded
	 * 
	 * @return bab_Path
	 */
	public function getFolder()
	{
		return $this->folder;
	}
	
	
	/**
	 * Force encoding method or disable encoding
	 * 
	 * <ul>
	 * 	<li>Widget_FilePicker::QPRINT : quoted printable, require php 5.3.0 or the imap extension</li>
	 *  <li>Widget_FilePicker::BASE64 : base 64, the most compatible</li>
	 *  <li>null : disable encoding</li>
	 * </ul>
	 * 
	 * @param string $method		Widget_FilePicker::QPRINT | Widget_FilePicker::BASE64 | null
	 * @return Widget_FilePicker
	 */
	public function setEncodingMethod($method)
	{
		$this->encoding = $method;
		return $this;
	}
	
	
	
	
	/**
	 * Returns the value, try to autodetect value from folder
	 *
	 * @return array
	 */
	public function getValue()
	{
		
		
		$path = $this->folder->toString();
		if (!file_exists($path) || !is_dir($path)) {
			return array();
		}
		
		$returnvalue = array();
		$d = dir($path);
		while (false !== ($entry = $d->read())) {
			if (is_file($path.'/'.$entry)) {
		   		$returnvalue[] = self::decode($entry);
			}
		}
		$d->close();
		
		
		return $returnvalue;
	}

	
	
	
	/**
	 * Unescape a string from filesystem and return readable value in database charset
	 * 
	 * @param string $str
	 * @return string
	 */
	public static function decode($str)
	{
		// prefix is ascii on filesystem, mb_string is not needed
		$prefix = substr($str, 0, self::PREFIX_LENGTH);
		$value = substr($str, self::PREFIX_LENGTH);
		
		switch($prefix) {
			case self::BASE64:
				
				$iPos = mb_strrpos($value, ".");
				if (false !== $iPos)
			    {
			    	$root = base64_decode(mb_substr($value, 0, $iPos));
			        $ext = mb_substr($value,$iPos);
			        return $root.$ext;
			        
			    } else {
					return base64_decode($value);
			    }
				
			case self::QPRINT:
				return quoted_printable_decode($value);

			case self::NONE:
				return $value;
		}
		
		return $str;
	}
	
	/**
	 * Escape a string before writing into filesystem
	 * 
	 * @param string $str
	 * @param string $encoding		Widget_FilePicker::QPRINT | Widget_FilePicker::BASE64 | null
	 * 
	 * @return string
	 */
	private static function encode($str, $encoding)
	{
		// try to not encode extension
		
		switch($encoding) {
			case self::BASE64:
				
				$iPos = mb_strrpos($str, ".");
		    	if (false !== $iPos)
			    {
			    	
			    	$root = mb_substr($str, 0, $iPos);
			        $ext = mb_substr($str,$iPos);
			        
			        if (preg_match('/[a-zA-Z0-9]+/', $ext)) {
			        	return self::BASE64.base64_encode($root).$ext;
			        }
			    }
			    
				return self::BASE64.base64_encode($str);

				
			case self::QPRINT:
				
				if (function_exists('quoted_printable_encode')) {
					$str = quoted_printable_encode($str);
					
				} elseif (function_exists('imap_8bit')) {
					
					$str = imap_8bit($str);
				} else {
					throw new Exception('the quoted printable encoding type need the php imap extension or php 5.3.0');
				}
				
				// imap_8bit add line break every 76 chars, we don't need that for files names
					
				$aLines = explode('='.chr(13).chr(10), $str);
				$str = implode('', $aLines);
				
				return self::QPRINT.$str;
		}
		
		return self::NONE.$str;
	}
	
	
	/**
	 * Push a folder name into the associated folder and encode it
	 * @param	string	$name
	 * @return Widget_FilePicker
	 */
	public function push($name)
	{
		$this->folder->push(self::encode($name, $this->encoding));
		return $this;
	}
	
	
	/**
	 * Set maximum size for one uploaded file
	 * @param	int		$size		bytes
	 * @return Widget_FilePicker
	 */
	public function setMaxSize($size)
	{
		$this->maxsize = $size;
		return $this;
	}
	
	
	

	/**
	 * Defines an optional drop target associated to the file picker.
	 * (Files dropped on this item will be uploaded as if they
	 * had been selected with the filepicker).
	 * 
	 * @param widget_Item $item
	 * @return Widget_FilePicker
	 */	
	public function setAssociatedDropTarget(Widget_Displayable_Interface $item)
	{
		$this->associatedDropTarget = $item;
		return $this;
	}


	/**
	 * Get widget classes
	 * @see programs/widgets/Widget_Uploader#getClasses()
	 * 
	 * @return	array
	 */
	public function getClasses()
	{
		$classes = parent::getClasses();
		$classes[] = 'widget-filepicker';
		
		if ($this->getMetadata('one_file_mode')) {
			$classes[] = 'widget-filepicker-onefilemode';
		}
		
		return $classes;
	}

	
	/**
	 * Set informations in session to upload file(s) in next page
	 * 
	 * @see Func_Widgets::onBeforePageCreated()
	 * 
	 * @return unknown_type
	 */
	private function addNextPageJob()
	{
		// remove previous jobs
		unset($_SESSION['addon_widgets'][__CLASS__][$this->getMetadata('uploadOrDeleteUid')]);
		unset($_SESSION['addon_widgets'][__CLASS__][$this->getMetadata('thumbnailUid')]);
		
		$_SESSION['addon_widgets'][__CLASS__][$this->getMetadata('uploadOrDeleteUid')] = array(
		
			'method' => 'uploadOrDelete',
			'params' => array(
				$this->getId(),
				$this->folder->toString(),
				$this->encoding,
				$this->getMetadata('one_file_mode'),
				$this->getAcceptedMimeTypes(),
				$this->maxsize
			)
		);
		
		
		$_SESSION['addon_widgets'][__CLASS__][$this->getMetadata('thumbnailUid')] = array(
		
			'method' => 'getThumbnail',
			'params' => array(
				$this->folder->toString(),
				$this->encoding,
				$this->thumbWidth,
				$this->thumbHeight
			)
		);
		
		
		
	}

	/**
	 * Upload files to folder; delete file from folder, do not call directly
	 * 
	 * @param	string		$widget_id
	 * @param 	string	 	$path
	 * @param	string		$encoding			encoding method
	 * @param	bool		$one_file_mode
	 * @param	array		$acceptedMimeTypes
	 * @param	int			$maxsize			
	 * 
	 * @return unknown_type
	 */
	public static function uploadOrDelete($widget_id, $path, $encoding, $one_file_mode, $acceptedMimeTypes, $maxsize)
	{
		
		$folder = new bab_Path($path); 
		
		
		// bug vu sur IIS :
		// <b>Warning</b>:  Unknown: 1 result set(s) not freed. Use mysql_free_result to free result sets which were requested using mysql_query() in <b>Unknown</b> on line <b>0</b><br />
		
		ini_set('mysql.trace_mode', 'Off');
		
		try {
			if (!isset($_FILES[$widget_id])) {
				// no file uploaded
				// throw new Exception(widget_translate('No file uploaded'));
				
				if ($delete = bab_rp('deletefile')) {
					// remove file if exists
					
					$delete = bab_getStringAccordingToDataBase($delete, 'UTF-8');
					
					$iterator = new Widget_FilePickerIterator($folder);
					foreach($iterator as $file) {
						
						if ($file->toString() === $delete) {
							try {
								$file->delete();
								die('OK');
								
							} catch(Exception $e) {
								die($e->getMessage());
							}
						}
					}
					
					die(widget_translate('The file does not exists'));	
					
				} else if($fileurl = bab_rp('addFileFromUrl')) {
					
					$filename = basename($fileurl);
					
					// try to get extension
					$ext = '';
					$iPos = mb_strrpos($filename, '.');
				    if (false !== $iPos) {
				        $ext = mb_substr($filename, $iPos);
				        if (strlen($ext) > 5) {
				        	$ext = '';
				        }
				    }
					
					// hack for long filenames and unsignificant url
					if (strlen($filename) > 25) {
						$filename = parse_url($fileurl, PHP_URL_HOST);
						$iPos1 = mb_strrpos($filename, '.');
				    	if (false !== $iPos1) {
				    		$filename = mb_substr($filename, 0, ($iPos1));
				    		if (false === $iPos2 = mb_strrpos($filename, '.')) {
				    			$iPos2 = 0;
				    		}
				    		$filename = mb_substr($filename, $iPos2+1);
				    	}
				    	
						$filename .= $ext;
					}
					
					$arr = array();
					$folder->createDir();
					$I = new Widget_FilePickerIterator($folder);
					foreach($I as $currentfile) {
						$arr[$currentfile->toString()] = true;
					}
					
					while(isset($arr[$filename])) {
						$filename = '1-'.$filename;
					}
					
					$dest = clone $folder;
					
					// remove folder in one file mode
					if (is_dir($folder->toString()) && $one_file_mode) {
						$folder->deleteDir();
					}
					
					$folder->createDir();
					
					$dest->push(self::encode($filename, $encoding));
					
					// set user_agent of php the same as user, hack for facebook or similar sites filtered by browsers
					ini_set('user_agent', $_SERVER['HTTP_USER_AGENT']);
					
					if (!@copy($fileurl, $dest->toString())) {
						die(widget_translate("The file can't be downloaded from the internet to the web server"));
					}
					
					die('OK'.$filename);
					
				} else {
					return;
				}
			}
			
			
			
			// remove folder in one file mode
			if (is_dir($folder->toString()) && $one_file_mode) {
				$folder->deleteDir();
			}
			
			// try to create folder if not exists
			if (false === $folder->createDir()) {
				throw new Exception('Error while creating destination folder '.$path);
				return;
			}
			
			if (isset($_FILES[$widget_id]['name']) && is_array($_FILES[$widget_id]['name'])) {
				
				$files = array();
				foreach($_FILES[$widget_id] as $key => $property) {
					foreach($property as $filenumber => $value) {
						$files[$filenumber][$key] = $value;
					}
				}
				
				foreach($files as $uploadinfo) {
					self::upload($folder, $uploadinfo, $encoding, $acceptedMimeTypes, $maxsize);
				}
				
			} else {
				self::upload($folder, $_FILES[$widget_id], $encoding, $acceptedMimeTypes, $maxsize);
			}
			
		} catch(Exception $e) {
		
			if ('ajax' === bab_rp('request_mode')) {
				die($e->getMessage());
			}
			
			// trigger_error($e->getMessage());
		}
		
		if ('ajax' === bab_rp('request_mode')) {
			die('OK');
		}
	}
	
	/**
	 * Upload one file
	 * @param 	bab_Path 	$folder
	 * @param 	array 		$uploadinfo
	 * @param	string		$encoding
	 * @param	array		$acceptedMimeTypes
	 * @param	int			$maxsize			Kb for one file
	 * @return unknown_type
	 */
	private static function upload($folder, $uploadinfo, $encoding, $acceptedMimeTypes, $maxsize)
	{
		require_once $GLOBALS['babInstallPath'].'utilit/uploadincl.php';
		$upload = bab_fileHandler::upload($uploadinfo);
					
		if ($upload->error && $upload->code !== UPLOAD_ERR_NO_FILE) {
			throw new Exception($upload->error);
			return;
		}
		
		if (0 !== count($acceptedMimeTypes)) {
			if (!in_array($upload->mime, $acceptedMimeTypes)) {
				throw new Exception(widget_translate('This type of file is not allowed'));
				return;
			}
		}
		
		if (null !== $maxsize) {
			if ($maxsize < $upload->size)
			{
				throw new Exception(sprintf(widget_translate('The file %s (%01.2f Kb) is bigger than the maximum allowed to upload (%d Kb)'), $upload->filename, $upload->size / 1024, round($maxsize / 1024)));
				return;
			}
		}
		
		
		$destination = clone $folder;

		$destination->push(self::encode($upload->filename, $encoding));
		$upload->import($destination->toString());
		
		unset($destination);
	}
	
	
	
	
	public static function getThumbnail($path, $encoding, $width, $height)
	{
		
		// bug vu sur IIS :
		// <b>Warning</b>:  Unknown: 1 result set(s) not freed. Use mysql_free_result to free result sets which were requested using mysql_query() in <b>Unknown</b> on line <b>0</b><br />
		
		ini_set('mysql.trace_mode', 'Off');
		
		
		
		
		if (!isset($_GET['thumbfile']) ) {
			
			return null;
		}
		
		
		$url = self::getImageUrl(new bab_Path($path), bab_rp('thumbfile'), $encoding, $width, $height);
		if (null === $url) {
			die('OK');
		}
		
		die($url);
	}
	
	
	
	
	/**
	 * Remove expired temporary files
	 * 
	 */ 
	private function cleanupExpired()
	{
		$sessions = array();
		foreach(bab_getActiveSessions() as $arr) {
			$sessions[$arr['session_id']] = 1;
		}
		
		$addon = bab_getAddonInfosInstance('widgets');
		$folder = new bab_Path($addon->getUploadPath());
		$folder->push(__CLASS__);
		$path = $folder->toString();
		
		if (!is_dir($path)) {
			return;
		}
		
		$d = dir($path);
		while (false !== ($entry = $d->read())) {
			if (!isset($sessions[$entry]) && '.' !== $entry && '..' !== $entry) {
				$expired = new bab_Path($path, $entry);
				
				if (!method_exists($expired, 'deleteDir')) {
					bab_debug('ovidentia is too old, no cleanup');
					return;
				}
				
				$expired->deleteDir();
			}
		}
	}
	
	
	
	/**
	 * Remove temporary directory for session
	 * 
	 */
	public function cleanup()
	{

		$addon = bab_getAddonInfosInstance('widgets');
		$folder = new bab_Path($addon->getUploadPath());
		$folder->push(__CLASS__);
		$folder->push(session_id());
		try {
			$folder->deleteDir();
		} catch(Exception $e) {
			// already clean
		}
		
		if (isset($_SESSION['addon_widgets'][__CLASS__])) {
			unset($_SESSION['addon_widgets'][__CLASS__]);
		}
	}
	
	/**
	 * Get temporary files full path by widget name
	 * 
	 * @param	string	$name		form field name used in widget
	 * 
	 * @return Widget_FilePickerIterator
	 */
	public function getTemporaryFiles($name)
	{
		
		$addon = bab_getAddonInfosInstance('widgets');
		$folder = new bab_Path($addon->getUploadPath());
		$folder->push(__CLASS__);
		$folder->push(session_id());
		$folder->push($name);
		
		return $this->getFolderFiles($folder);
	}
	
	
	/**
	 * Get files in path
	 * @param bab_Path $path
	 * @return Widget_FilePickerIterator | null
	 */
	public function getFolderFiles(bab_Path $path)
	{
		if (!is_dir($path->toString())) {
			bab_debug('no folder : '.$path->toString(), DBG_TRACE, __CLASS__);
			return null;
		}
		
		return new Widget_FilePickerIterator($path);
	}
	
	/**
	 * Import and encode a copy of a file into current folder
	 * @param	bab_Path 	$path				full path name of file to import
	 * @param	string		$source_encoding	filename encoding
	 * @return	bool
	 */
	public function importFile(bab_Path $path, $source_encoding)
	{
		$filename = basename($path->toString());
		$this->folder->createDir();
		$dest = clone $this->folder;
		$dest->push(self::encode(bab_getStringAccordingToDataBase($filename, $source_encoding), $this->encoding));
		
		return copy($path->toString(), $dest->toString());
	}
	
	
	/**
	 * Import and encode a copy of all files and folders into current folder
	 * @param bab_Path 	$src					source folder path
	 * @param string 	$source_encoding		filenames and foldernames encoding
	 * @return unknown_type
	 */
	public function importPath(bab_Path $src, $source_encoding)
	{
		foreach($src as $tmpFile)
		{
			if ($tmpFile->isDir())
			{
				$fp = clone $this;
				$fp->folder = clone $this->getFolder();
				
				$fp->folder->push(self::encode(bab_getStringAccordingToDataBase($tmpFile->getBasename(), $source_encoding), $this->encoding));
				$fp->importPath($tmpFile, $source_encoding);
				
			} else {
				$this->importFile($tmpFile, $source_encoding);
			}
		}
	}
	
	
	
	
	/**
	 * open a file in the filepicker folder with fopen
	 * 
	 * @param string $filename			
	 * @param string $source_encoding	filename encoding
	 * @param string $mode				fopen mode 'r' | 'w' | 'a' | 'rb'
	 * 
	 * @return ressource				fopen ressource
	 */
	public function openFile($filename, $source_encoding, $mode)
	{
		$this->folder->createDir();
		
		$dest = clone $this->folder;
		$dest->push(self::encode(bab_getStringAccordingToDataBase($filename, $source_encoding), $this->encoding));
		
		return fopen($dest->toString(), $mode);
	}
	
	
	
    /**
     * Get by encoded filename
     * 
     * @param string $encoded_filename
     * @return Widget_FilePickerItem
     */
    public function getByName(bab_Path $path, $encoded_filename) {
    	
    	return new Widget_FilePickerItem($path, $encoded_filename);
    }
    
    /**
     * get image url
     * try to use thumbnailer if available or use default icon
     * 
	 * @param	bab_Path	$folder		folder
	 * @param 	string 		$filename	not encoded filename
	 * @param	string		$encoding
	 * @param	int			$width
	 * @param	int			$height
	 * 
	 * @return string
	 */
    private static function getImageUrl(bab_Path $folder, $filename, $encoding, $width, $height)
    {
		$T = @bab_functionality::get('Thumbnailer', false);

		if ($T) {
			
			$path = clone $folder;
			$path->push(self::encode($filename, $encoding));
			$filepath = $path->toString();
			
			$icon = $T->getIcon($filepath, $width, $height);
			
			if (is_object($icon)) {
				return $icon->__toString();
			}
			
			return $icon;
		}
		
    	$addon = bab_getAddonInfosInstance('widgets');
		
		if ($height >= 48)
		{
			return $addon->getImagesPath().'48x48/application-octet-stream.png';
		}
		
    	if ($height >= 32)
		{
			return $addon->getImagesPath().'32x32/application-octet-stream.png';
		}
		
		return $addon->getImagesPath().'16x16/application-octet-stream.png';
    }
    
    /**
     * @param	string	$filename
     * @return string
     */
    private static function getFileDescription($filename)
    {
    	$F = bab_functionality::get('FileInfos');

		if ($F) {
			$mimetype = $F->getMimeTypeFromExtension($filename);
			return $F->getFileTypeFromMimeType($mimetype);
		}
		
		return '';
    	
    }
    
    
	/**
	 * got to this location after upload
	 * @param	Widget_Action	$action
	 * @return	Widget_FilePicker
	 */
	public function onUploadAction(Widget_Action $action)
	{
		$this->setMetadata('uploadAction', $action->url());
		$this->setMetadata('uploadActionAjax', $action->isAjax());
		return $this;	
	}
	
	/**
	 * Execute this javascript function after upload
	 * @param	string	$function
	 * @return	Widget_FilePicker
	 */
	public function onUpload($js_function, $domain = 'window.babAddonWidgets')
	{
		$arr = $this->getMetadata('uploadJs');
		$arr[] = $domain.'.'.$js_function;

		$this->setMetadata('uploadJs', $arr);
		return $this;
	}

    

	public function display(Widget_Canvas $canvas)
	{	
		$addon = bab_getAddonInfosInstance('widgets');
		if (!$addon->isAccessValid())
		{
			throw new Exception('The widget addon need to be installed to perform an upload with the file picker widget');
		}		
		
		$arrNames = $this->getFullName();
		$this->setMetadata('fullname', $canvas->getHtmlName($arrNames));
		
		$this->addNextPageJob();
		$this->cleanupExpired();
		
		// create a frame with hidden fields for the values to be in form submit
		$d = array();
		$h = array();

		if (isset($this->defaultImage)) {
			$d[] = $canvas->image(null, array('widget-filepicker-default-image'), '', $this->defaultImage);
		}
		
		foreach($this->getValue() as $filename) {
			
			$hArrName = $arrNames;
			$hArrName[] = '';
			
			if ($this->getMetaData('display_existing_files')) {
				
				$items = array();
				
				if ($imageurl = self::getImageUrl($this->folder, $filename, $this->encoding, $this->thumbWidth, $this->thumbHeight)) {
					$items[] = $canvas->div(null, array('widget-layout-vbox-item'), array($canvas->image(null, null, self::getFileDescription($filename), $imageurl)));
				}
				
				$items[] = $canvas->div(null, $this->getMetadata('deleteclasses'), array($filename));

				
				$d[] = $canvas->div(null, $this->getMetadata('fileclasses'), $items);
			}
			
			$h[] = $canvas->hidden(null, null, $hArrName, $filename);
		}
		
		$displayframe = $canvas->div(null, array('widget-filepicker-files'), $d);
		$valuesframe = $canvas->div(null, array('widget-filepicker-values'), $h);
		
		$multiple = !$this->getMetadata('one_file_mode') && '[]' === mb_substr($this->getName(), -2);
		

		if (isset($this->associatedDropTarget)) {
			$this->associatedDropTarget->addClass('widget-filepicker-drop-target');
			$this->setMetadata('droptarget', $this->associatedDropTarget->getId());
			$this->associatedDropTarget->setMetadata('filepicker', $this->getId());
		}
		
		// default uploader if no javascript
		
		$uploader = $canvas->fileUpload(null, null, array($this->getId()), $this->getAcceptedMimeTypes(),$this->getSize(), $multiple);

		if ($this->isDisplayMode()) {
			return $canvas->div(
				$this->getId(), 
				$this->getClasses(), 
				array(
					$displayframe
				)
			)
			.$canvas->metadata($this->getId(), $this->getMetadata());
		}
		
		return $canvas->div(
			$this->getId(), 
			$this->getClasses(), 
			array(
				$displayframe,
				$valuesframe,
				$uploader
			)
		)
		.$canvas->hidden(null, null, array('widget_filepicker_job_uid', ''), $this->getMetadata('uploadOrDeleteUid'))
		.$canvas->metadata($this->getId(), $this->getMetadata());
	}

}




/**
 * File uploaded with a FilePicker widget
 *
 */
class Widget_FilePickerItem 
{
	private $path = null;
	private $encoded_file_name = null;
	
	
	public function __construct(bab_Path $path, $encoded_file_name)
	{
		$this->path = $path;
		$this->encoded_file_name = $encoded_file_name;
	}
	
	/**
	 * Get original filename
	 * 
	 * @return string
	 */
	public function toString()
	{
		return Widget_FilePicker::decode($this->encoded_file_name);
	}
	
	/**
	 * 
	 * @return bab_Path
	 */
	public function getFilePath()
	{
		$filepath = clone $this->path;
		$filepath->push($this->encoded_file_name);
		
		return $filepath;
	}
	
	/**
	 * 
	 * @return string
	 */
	public function getFileName()
	{
		return $this->encoded_file_name;
	}
	
	/**
	 * 
	 * @return bool
	 */
	public function isDir()
	{
		$sFullPathName = $this->getFilePath()->toString();
		return @is_dir($sFullPathName);
	}
	
	/**
	 * Download the file to user
	 * 
	 * @param	bool	$inline
	 * 
	 * @return mixed
	 */
	public function download($inline = true)
	{
		$sFullPathName = $this->getFilePath()->toString();
		
		$fp = fopen($sFullPathName, 'rb');
		if ($fp) 
		{
			bab_setTimeLimit(3600);
	
			if (mb_strtolower(bab_browserAgent()) == 'msie') {
				header('Cache-Control: public');
			}
			
			if ($inline) {
				header('Content-Disposition: inline; filename="'.$this->toString().'"'."\n");
			} else {
				header('Content-Disposition: attachment; filename="'.$this->toString().'"'."\n");
			}
	
			$mime = bab_getFileMimeType($sFullPathName);
			$fsize = filesize($sFullPathName);
			header('Content-Type: '.$mime."\n");
			header('Content-Length: '.$fsize."\n");
			header('Content-transfert-encoding: binary'."\n");
	
			while (!feof($fp)) {
				print fread($fp, 8192);
			}
			fclose($fp);
			exit;
		}
	}
	
	/**
	 * Delete file if exists
	 * @throw Exception
	 * 
	 * @return bool
	 */
	public function delete()
	{
		$sFullPathName = $this->getFilePath()->toString();
		
		if (!file_exists($sFullPathName)) {
			throw new Exception(widget_translate('The file does not exists'));
			return false;
		}
		
		if (!is_writable($sFullPathName)) {
			throw new Exception(widget_translate('The file is not writable'));
			return false;
		}
		
		if (!@unlink($sFullPathName)) {
			throw new Exception(widget_translate('Error while deleting the file'));
			return false;
		}
		
		return true;
	}
}






/**
 * CSV result iterator
 * to browse the content of the uploaded CSV file
 */ 
class Widget_FilePickerIterator implements Iterator
{
	private $path 				= null;
	private $res				= null;
	private $key				= null;
	
	/**
	 * Constructor
	 * 
	 * @param	bab_Path	$path			folder to read
	 */ 
    public function __construct($path)
    {
        $this->path = $path;

    }

    public function rewind() {
        $this->res = dir($this->path->toString());
        $this->next();
    }


	/**
	 * 
	 * @return Widget_FilePickerItem
	 */ 
    public function current() {
        return new Widget_FilePickerItem($this->path, $this->key);
    }

    public function key() {
        return $this->key;
    }

    public function next() {
		do {
			$entry = $this->res->read();
		} while (false !== $entry && ('.' === $entry || '..' === $entry));
		
		$this->key = $entry;
    }

	/**
	 * 
	 * @return bool
	 */ 
    public function valid() {
		return (isset($this->key) && false !== $this->key);
    }


}





























